package com.southminority.ethnic.service.research.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.southminority.ethnic.common.exception.BusinessException;
import com.southminority.ethnic.common.result.PageResult;
import com.southminority.ethnic.mapper.research.ResearchProjectMapper;
import com.southminority.ethnic.pojo.ResearchProject;
import com.southminority.ethnic.service.research.ResearchProjectService;
import com.southminority.ethnic.controller.research.vo.ResearchProjectVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 科研项目服务实现类.
 * <p>
 * 实现了 {@link ResearchProjectService} 接口，负责处理所有与科研项目相关的业务逻辑。
 * 包括数据查询、转换、增删改查等操作，并处理了多个JSON格式字段的序列化与反序列化。
 * 
 * @author SouthMinority
 */
@Slf4j
@Service
@Transactional
public class ResearchProjectServiceImpl implements ResearchProjectService {

    private final ResearchProjectMapper researchProjectMapper;
    private final ObjectMapper objectMapper;

    public ResearchProjectServiceImpl(ResearchProjectMapper researchProjectMapper, ObjectMapper objectMapper) {
        this.researchProjectMapper = researchProjectMapper;
        this.objectMapper = objectMapper;
    }

    // =================================================================================
    // ==                             前端展示相关方法 (Public API)                     ==
    // =================================================================================

    @Override
    public PageResult<ResearchProjectVO> getPublishedProjectPage(Integer page, Integer size, String projectType, String level, Integer year) {
        Page<ResearchProject> pageObj = new Page<>(page, size);
        QueryWrapper<ResearchProject> wrapper = new QueryWrapper<>();

        wrapper.eq("status", 1);
        if (StringUtils.hasText(projectType)) {
            wrapper.eq("project_type", projectType);
        }
        if (StringUtils.hasText(level)) {
            wrapper.eq("level", level);
        }
        if (year != null) {
            wrapper.eq("start_year", year);
        }

        wrapper.orderByDesc("is_featured").orderByAsc("sort_order").orderByDesc("start_year");

        IPage<ResearchProject> pageResult = researchProjectMapper.selectPage(pageObj, wrapper);
        List<ResearchProjectVO> voList = pageResult.getRecords().stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());

        return PageResult.<ResearchProjectVO>builder()
                .current(pageResult.getCurrent())
                .size(pageResult.getSize())
                .total(pageResult.getTotal())
                .pages(pageResult.getPages())
                .records(voList)
                .build();
    }

    @Override
    public ResearchProjectVO getProjectDetail(Long id) {
        ResearchProject project = researchProjectMapper.selectById(id);
        if (project == null || project.getStatus() != 1) {
            throw new BusinessException("科研项目不存在或未发布");
        }
        return convertToVO(project);
    }

    @Override
    public List<String> getProjectLevels() {
        QueryWrapper<ResearchProject> wrapper = new QueryWrapper<>();
        wrapper.select("DISTINCT level")
               .eq("status", 1)
               .isNotNull("level")
               .orderByAsc("level");
        
        return researchProjectMapper.selectList(wrapper).stream()
                                  .map(ResearchProject::getLevel)
                                  .filter(StringUtils::hasText)
                                  .collect(Collectors.toList());
    }

    @Override
    public List<Integer> getProjectStartYears() {
        QueryWrapper<ResearchProject> wrapper = new QueryWrapper<>();
        wrapper.select("DISTINCT start_year")
               .eq("status", 1)
               .isNotNull("start_year")
               .orderByDesc("start_year");

        return researchProjectMapper.selectList(wrapper).stream()
                                  .map(ResearchProject::getStartYear)
                                  .collect(Collectors.toList());
    }

    // =================================================================================
    // ==                             后台管理相关方法 (Admin API)                      ==
    // =================================================================================

    @Override
    public PageResult<ResearchProjectVO> getProjectPageForAdmin(Integer page, Integer size, String keyword, String projectType, String level, Integer status) {
        Page<ResearchProject> pageObj = new Page<>(page, size);
        QueryWrapper<ResearchProject> wrapper = new QueryWrapper<>();
        
        if (StringUtils.hasText(keyword)) {
            wrapper.and(qw -> qw.like("title", keyword)
                               .or().like("principal_investigator", keyword));
        }
        if (StringUtils.hasText(projectType)) {
            wrapper.eq("project_type", projectType);
        }
        if (StringUtils.hasText(level)) {
            wrapper.eq("level", level);
        }
        if (status != null) {
            wrapper.eq("status", status);
        } else {
            wrapper.ne("status", -1);
        }
        
        wrapper.orderByDesc("is_featured").orderByAsc("sort_order").orderByDesc("start_year");
        
        IPage<ResearchProject> pageResult = researchProjectMapper.selectPage(pageObj, wrapper);
        List<ResearchProjectVO> voList = pageResult.getRecords().stream()
                                                   .map(this::convertToVO)
                                                   .collect(Collectors.toList());
        
        return PageResult.<ResearchProjectVO>builder()
                .current(pageResult.getCurrent())
                .size(pageResult.getSize())
                .total(pageResult.getTotal())
                .pages(pageResult.getPages())
                .records(voList)
                .build();
    }

    @Override
    public ResearchProjectVO getProjectDetailForAdmin(Long id) {
        ResearchProject project = researchProjectMapper.selectById(id);
        if (project == null) {
            throw new BusinessException("科研项目不存在");
        }
        return convertToVO(project);
    }

    @Override
    public ResearchProjectVO createProject(ResearchProject project) {
        if (project == null) {
            throw new BusinessException("项目信息不能为空");
        }
        project.setCreateTime(LocalDateTime.now());
        project.setUpdateTime(LocalDateTime.now());
        researchProjectMapper.insert(project);
        return convertToVO(project);
    }

    @Override
    public ResearchProjectVO updateProject(Long id, ResearchProject project) {
        ResearchProject existingProject = researchProjectMapper.selectById(id);
        if (existingProject == null) {
            throw new BusinessException("科研项目不存在");
        }
        
        project.setId(id);
        project.setUpdateTime(LocalDateTime.now());
        researchProjectMapper.updateById(project);
        return convertToVO(researchProjectMapper.selectById(id));
    }

    @Override
    public boolean deleteProject(Long id) {
        ResearchProject project = researchProjectMapper.selectById(id);
        if (project == null) {
            return true;
        }
        
        project.setStatus(-1);
        project.setUpdateTime(LocalDateTime.now());
        return researchProjectMapper.updateById(project) > 0;
    }

    @Override
    public boolean batchDeleteProjects(List<Long> ids) {
        if (ids == null || ids.isEmpty()) {
            throw new BusinessException("ID列表不能为空");
        }
        
        List<ResearchProject> projectList = researchProjectMapper.selectBatchIds(ids);
        if (projectList.isEmpty()) {
            return true;
        }
        
        LocalDateTime now = LocalDateTime.now();
        for (ResearchProject project : projectList) {
            project.setStatus(-1);
            project.setUpdateTime(now);
            researchProjectMapper.updateById(project);
        }
        return true;
    }

    @Override
    public boolean updateProjectStatus(Long id, Integer status) {
        ResearchProject project = researchProjectMapper.selectById(id);
        if (project == null) {
            throw new BusinessException("科研项目不存在");
        }
        if (status == null || (status < -1 || status > 1)) {
            throw new BusinessException("无效的状态值");
        }
        
        project.setStatus(status);
        project.setUpdateTime(LocalDateTime.now());
        return researchProjectMapper.updateById(project) > 0;
    }

    @Override
    public boolean setProjectFeatured(Long id, Integer isFeatured) {
        ResearchProject project = researchProjectMapper.selectById(id);
        if (project == null) {
            throw new BusinessException("科研项目不存在");
        }
        if (isFeatured == null || (isFeatured != 0 && isFeatured != 1)) {
            throw new BusinessException("无效的置顶值");
        }
        
        project.setIsFeatured(isFeatured);
        project.setUpdateTime(LocalDateTime.now());
        return researchProjectMapper.updateById(project) > 0;
    }

    @Override
    public List<ResearchProjectVO> getAllProjectsForAdmin() {
        QueryWrapper<ResearchProject> wrapper = new QueryWrapper<>();
        // 过滤逻辑删除的数据
        wrapper.ne("status", -1).orderByDesc("create_time");
        List<ResearchProject> list = researchProjectMapper.selectList(wrapper);
        return list.stream().map(this::convertToVO).collect(Collectors.toList());
    }

    // =================================================================================
    // ==                             私有辅助方法 (Private Helpers)                      ==
    // =================================================================================

    /**
     * 将 ResearchProject POJO 转换为 ResearchProjectVO DTO.
     * <p>
     * 此方法负责处理复杂数据类型的转换，例如将数据库中存储的JSON字符串
     * 转换为Java的List，以便前端可以直接使用。
     *
     * @param project 数据库实体对象
     * @return 用于前端展示的视图对象
     */
    private ResearchProjectVO convertToVO(ResearchProject project) {
        if (project == null) return null;

        ResearchProjectVO vo = new ResearchProjectVO();
        BeanUtils.copyProperties(project, vo);
        
        try {
            if (StringUtils.hasText(project.getMembers())) {
                vo.setMembers(objectMapper.readValue(project.getMembers(), new TypeReference<>() {}));
            } else {
                vo.setMembers(Collections.emptyList());
            }
            if (StringUtils.hasText(project.getOutcomes())) {
                vo.setOutcomes(objectMapper.readValue(project.getOutcomes(), new TypeReference<>() {}));
            } else {
                vo.setOutcomes(Collections.emptyList());
            }
            if (StringUtils.hasText(project.getPublications())) {
                vo.setPublications(objectMapper.readValue(project.getPublications(), new TypeReference<>() {}));
            } else {
                vo.setPublications(Collections.emptyList());
            }
            if (StringUtils.hasText(project.getAttachmentUrls())) {
                vo.setAttachmentUrls(objectMapper.readValue(project.getAttachmentUrls(), new TypeReference<>() {}));
            } else {
                vo.setAttachmentUrls(Collections.emptyList());
            }
        } catch (JsonProcessingException e) {
            log.error("解析项目(ID:{})的JSON字段失败: {}", project.getId(), e.getMessage());
            vo.setMembers(Collections.emptyList());
            vo.setOutcomes(Collections.emptyList());
            vo.setPublications(Collections.emptyList());
            vo.setAttachmentUrls(Collections.emptyList());
        }
        
        return vo;
    }
} 
